package com.ruoyi.web.Server;

import com.alibaba.fastjson.JSON;
import com.ruoyi.web.Server.BT.TorrentService;
import com.ruoyi.web.dao.sys.UserDao;
import com.ruoyi.web.domain.BT.TorrentEntity;
import com.ruoyi.web.domain.BT.TorrentPeerEntity;
import com.ruoyi.web.domain.sys.UserEntity;
import com.ruoyi.web.dao.BT.AnnounceRequest;
import com.ruoyi.web.dao.BT.TrackerResponse;
import com.ruoyi.web.Server.sys.UserService;
import com.ruoyi.web.Server.validator.ValidationManager;
import com.ruoyi.web.Server.BT.TorrentPeerService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.temporal.ChronoUnit;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

@Service
@Slf4j
@RequiredArgsConstructor
public class AnnounceService {

    final UserDao userDao;
    final UserService userService;
    final TorrentPeerService torrentPeerService;
    final ValidationManager validationManager;
    final TorrentService torrentService;

    public Map<String, Object> announce(AnnounceRequest request) {
        boolean noPeerId = request.isNoPeerId();
        byte[] infoHash = request.getInfoHash();
        TorrentEntity torrent = torrentService.getByInfoHash(infoHash);
        if (torrent == null){
            torrent = torrentService.getById(Integer.parseInt(request.getTorrentId()));
            request.setInfoHash(torrent.getInfoHash());
        }
        request.setTorrent(torrent);

        UserEntity user = userDao.findUserByPasskey(request.getPasskey());
        request.setUser(user);
        // 先更新peer状态再获取列表
        updatePeer(request);

        List<Map<String, Object>> peerList = getPeerList(request, 200);
        updateUserInfo(request);

        // 使用动态广播间隔
        Integer interval = getAnnounceInterval(request);
        TrackerResponse trackerResponse = TrackerResponse.build(
                interval, 60,
                torrent.getSeeders(),
                torrent.getLeechers(),
                peerList,
                1
        );
        return trackerResponse.toResultMap();
    }

    private void updateUserInfo(AnnounceRequest request) {
        UserEntity user = request.getUser();
        TorrentEntity torrent = request.getTorrent();
        Integer userId = user.getUserId().intValue();
        Integer torrentId = torrent.getId();
        byte[] peerId = request.getPeerId();

        // 确保peer记录存在
        TorrentPeerEntity peer = torrentPeerService.getPeer(userId, torrentId, peerId);
        if (peer == null) {
            peer = tryInsertOrUpdatePeer(request);
            if (peer == null) return; // 创建失败则终止
        }

        // 处理负增量问题
        long lastUploaded = peer.getUploaded();
        long lastDownloaded = peer.getDownloaded();
        long currentUploaded = request.getUploaded();
        long currentDownloaded = request.getDownloaded();

        long uploadedOffset = Math.max(currentUploaded - lastUploaded, 0);
        long downloadedOffset = Math.max(currentDownloaded - lastDownloaded, 0);

        // 使用原子操作更新用户数据
        userService.updateUserStats(
                userId,
                uploadedOffset,
                downloadedOffset,
                calculateSeedTimeIncrement(peer, request)
        );
    }

    // 精确计算做种时间增量（毫秒）
    private long calculateSeedTimeIncrement(TorrentPeerEntity peer, AnnounceRequest request) {
        if (!request.getSeeder()) return 0;

        long now = System.currentTimeMillis();
        long lastAnnounceTime = peer.getLastAnnounce().atZone(ZoneOffset.UTC).toInstant().toEpochMilli();
        return now - lastAnnounceTime;
    }

    // 简化事件处理逻辑
    public void updatePeer(AnnounceRequest request) {
        String event = StringUtils.trimToEmpty(request.getEvent());
        log.info("Peer event {}: {}", event, JSON.toJSONString(request, true));
        byte[] infoHash = request.getInfoHash();
        TorrentEntity torrent = torrentService.getByInfoHash(infoHash);
        request.setTorrent(torrent);
        UserEntity user = userDao.findUserByPasskey(request.getPasskey());
        request.setUser(user);
        Integer userId = userDao.findUserByPasskey(request.getPasskey()).getUserId().intValue();
        Integer torrentId = request.getTorrent().getId();
        String peerIdHex = request.getPeerIdHex();

        // 处理停止事件
        if (AnnounceRequest.EventType.stopped.equalsIgnoreCase(event)) {
            if (torrentPeerService.peerExists(userId, torrentId, peerIdHex.getBytes())) {
                torrentPeerService.delete(userId, torrentId, peerIdHex);
            }
            return;
        }

        // 其他事件统一更新
        TorrentPeerEntity updatedPeer = tryInsertOrUpdatePeer(request);
        if (updatedPeer != null && AnnounceRequest.EventType.completed.equalsIgnoreCase(event)) {
            // 标记种子完成
            updatedPeer.setSeeder(true);
            torrentPeerService.updateById(updatedPeer);
        }
    }

    // 优化peer列表获取

    // 优化peer列表获取
    private List<Map<String, Object>> getPeerList(AnnounceRequest request, Integer peerNumWant) {
        Integer torrentId = request.getTorrent().getId();
        boolean isSeeder = request.getSeeder();
        boolean noPeerId = request.isNoPeerId();
        Integer userId = userDao.findUserByPasskey(request.getPasskey()).getUserId().intValue();

        String peerIdHex = request.getPeerIdHex();

        // 动态调整获取数量
        int actualPeerNum = Math.min(peerNumWant, 200);

        List<TorrentPeerEntity> peers = torrentPeerService.listByTorrent(
                torrentId,
                isSeeder,
                actualPeerNum
        );

        return peers.stream()
                .filter(peerEntity -> !isSelfPeer(peerEntity, userId, peerIdHex)) // 修复变量冲突
                .map(peerEntity -> buildPeerMap(peerEntity, noPeerId)) // 修复变量冲突
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
    }

    // 新增：检查是否是自身peer
    private boolean isSelfPeer(TorrentPeerEntity peer, Integer userId, String peerIdHex) {
        return peer.getUserId().equals(userId) && peer.getPeerId().equals(peerIdHex);
    }
    // 构建peer返回数据
    private Map<String, Object> buildPeerMap(TorrentPeerEntity peer, boolean noPeerId) {
        Map<String, Object> dataMap = new HashMap<>();

        if (StringUtils.isNotBlank(peer.getIp())) {
            dataMap.put("ip", peer.getIp());
            dataMap.put("port", peer.getPort());
            if (!noPeerId) {
                dataMap.put("peer id", peer.getPeerId());
            }
        }
        // IPv6支持
        if (StringUtils.isNotBlank(peer.getIpv6())) {
            dataMap.put("ipv6", peer.getIpv6());
            dataMap.put("port", peer.getPort()); // 端口复用
        }

        return dataMap.isEmpty() ? null : dataMap;
    }

    // 修复peer更新逻辑
    private TorrentPeerEntity tryInsertOrUpdatePeer(AnnounceRequest request) {
        Integer userId = userDao.findUserByPasskey(request.getPasskey()).getUserId().intValue();

        Integer torrentId = request.getTorrent().getId();
        String peerIdHex = request.getPeerIdHex();

        try {
            // 先尝试获取现有记录
            TorrentPeerEntity peer = torrentPeerService.getPeer(userId, torrentId, peerIdHex.getBytes());
            boolean isNew = false;

            if (peer == null) {
                peer = new TorrentPeerEntity();
                peer.setCreateTime(LocalDateTime.now());
                isNew = true;
            }

            // 更新关键字段
            peer.setUserId(userId);
            peer.setTorrentId(torrentId);
            peer.setPeerId(request.getPeer_id());
            peer.setPeerIdHex(peerIdHex);
            peer.setPort(request.getPort());
            peer.setDownloaded(request.getDownloaded());
            peer.setUploaded(request.getUploaded());
            peer.setRemaining(request.getLeft());
            peer.setSeeder(request.getSeeder());
            peer.setUserAgent(request.getUserAgent());
            peer.setPasskey(request.getPasskey());
            peer.setLastAnnounce(LocalDateTime.now());
            peer.setIp(StringUtils.defaultIfBlank(request.getIp(), request.getRemoteAddr()));
            peer.setIpv6(request.getIpv6());

            if (isNew) {
                torrentPeerService.insertOrUpdate(peer);
            } else {
                torrentPeerService.updateById(peer);
            }
            return peer;

        } catch (Exception e) {
            log.error("Peer update error: ", e);
            return null;
        }
    }

    // 实现动态广播间隔策略
    private Integer getAnnounceInterval(AnnounceRequest request) {
        TorrentEntity torrent = request.getTorrent();
        int activePeers = torrent.getSeeders() + torrent.getLeechers();
        long daysActive = ChronoUnit.DAYS.between(torrent.getCreateTime(), LocalDateTime.now());

        // 动态调整策略
        if (daysActive < 7 || activePeers > 1000) {
            return 600; // 高频更新（10分钟）
        } else if ((daysActive >= 7 && daysActive < 30) ||
                (activePeers >= 100 && activePeers <= 1000)) {
            return 1800; // 中频更新（30分钟）
        } else {
            return 3600; // 低频更新（60分钟）
        }
    }
}
